package com.jservice.web.editor;

import com.baidu.ueditor.PathFormat;
import com.baidu.ueditor.define.AppInfo;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.MultiState;
import com.baidu.ueditor.define.State;
import com.baidu.ueditor.manager.AbstractFileManager;
import com.jservice.framework.dto.Setting;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.util.*;

/**
 * NeditorFileManager
 *
 * @Author cwledit
 * @DATE 2017/7/6.
 */
public class NeditorFileManager extends AbstractFileManager {

    public static final int BUFFER_SIZE = 1024 * 8;

    private State getState(String rootPath, File[] files) {
        MultiState state = new MultiState(true);

        for (File file : files) {
            if (file == null) {
                break;
            }
            BaseState fileState = new BaseState(true);
            String path = file.getAbsolutePath()
                    .replace(rootPath, "/")
                    .replace("\\", "/")
                    .replace("//", "/");

            fileState.putInfo("url", Setting.getConfig("imagehost")+PathFormat.format(path));
            state.addState(fileState);
        }

        return state;
    }

    /**
     * 文件列表 - 增加网站路径
     * @param conf 配置
     * @param start 开始
     * @return state 状态接口
     */
    @Override
    public State list(Map<String, Object> conf, int start) {
        String rootPath = (String) conf.get("rootPath");
        String dirPath = rootPath + (String) conf.get("dir");
        List<String> allowFiles = getAllowFiles(conf.get("allowFiles"));
        int count = (Integer) conf.get("count");

        File dir = new File(dirPath);

        if (!dir.exists()) {
            return new BaseState(false, AppInfo.NOT_EXIST);
        }

        if (!dir.isDirectory()) {
            return new BaseState(false, AppInfo.NOT_DIRECTORY);
        }

        Collection<File> list = FileUtils.listFiles(dir, allowFiles.toArray(new String[0]), true);

        Collections.reverse((List<File>) list);

        State state = null;
        if (start < 0 || start > list.size()) {
            state = new MultiState(true);
        } else {
            File[] fileList = Arrays.copyOfRange(list.toArray(new File[0]), start, start + count);
            state = getState(rootPath, fileList);
        }

        state.putInfo("start", start);
        state.putInfo("total", list.size());

        return state;
    }

    /**
     * 保存二进制文件
     * @param data 图片二进制信息
     * @param rootPath 跟路径
     * @param savePath 保存路径
     * @return state 状态接口
     */
    @Override
    public State saveFile(byte[] data, String rootPath, String savePath) {
        File file = new File(rootPath + savePath);

        State state = valid(file);
        if (!state.isSuccess()) {
            return state;
        }

        try {
            FileUtils.writeByteArrayToFile(file, data);
        } catch (IOException ioe) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        state = new BaseState(true, file.getAbsolutePath());

        state.putInfo("size", data.length);
        state.putInfo("title", file.getName());
        return state;
    }

    @Override
    public State saveFile(InputStream is, String rootPath, String savePath, long maxSize) {
        byte[] dataBuf = new byte[BUFFER_SIZE];
        BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);

        try {
            File tmpFile = getTmpFile();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), BUFFER_SIZE);

            int count = 0;
            while ((count = bis.read(dataBuf)) != -1) {
                bos.write(dataBuf, 0, count);
            }
            bos.flush();
            bos.close();

            if (tmpFile.length() > maxSize) {
                tmpFile.delete();
                return new BaseState(false, AppInfo.MAX_SIZE);
            }

            State state = saveTmpFile(tmpFile, rootPath + savePath);

            if (!state.isSuccess()) {
                tmpFile.delete();
            }

            return state;

        } catch (IOException e) {
            // ignore
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    @Override
    public State saveFile(InputStream is, String rootPath, String savePath) {
        byte[] dataBuf = new byte[BUFFER_SIZE];
        BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
        State state = null;
        try {
            File tmpFile = getTmpFile();
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile), BUFFER_SIZE);

            int count = 0;
            while ((count = bis.read(dataBuf)) != -1) {
                bos.write(dataBuf, 0, count);
            }
            bos.flush();
            bos.close();

            state = saveTmpFile(tmpFile, rootPath + savePath);

            if (!state.isSuccess()) {
                tmpFile.delete();
            }

            return state;
        } catch (IOException e) {
            // ignore
        }
        return new BaseState(false, AppInfo.IO_ERROR);
    }

    private static File getTmpFile() throws IOException {
        File tmpDir = FileUtils.getTempDirectory();
        if (!tmpDir.exists()) {
            FileUtils.forceMkdir(tmpDir);
        }

        String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
        return new File(tmpDir, tmpFileName);
    }

    private static State saveTmpFile(File tmpFile, String path) {
        File targetFile = new File(path);

        if (targetFile.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }
        try {
            FileUtils.moveFile(tmpFile, targetFile);
        } catch (IOException e) {
            return new BaseState(false, AppInfo.IO_ERROR);
        }

        State state = new BaseState(true);
        state.putInfo("size", targetFile.length());
        state.putInfo("title", targetFile.getName());

        return state;
    }

    private static State valid(File file) {
        File parentPath = file.getParentFile();

        if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
            return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
        }

        if (!parentPath.canWrite()) {
            return new BaseState(false, AppInfo.PERMISSION_DENIED);
        }

        return new BaseState(true);
    }

}
